import asyncio
import time

async def delay_print(text,delay):
    print(await asyncio.sleep(delay,result=text))



async def main_order():
    print(time.time())
    await delay_print('1秒后打印',1)
    print(time.time())
    await delay_print('2秒后打印',1)
    print(time.time())
    await delay_print('3秒后打印',1)
    print(time.time())

async def main():
    delay = 3
    print_ontime = delay_print(f"{delay} 秒后打印",delay)
    await asyncio.wait_for(print_ontime,timeout=delay+1)
    print_timeout = delay_print(f"{delay+1} 秒后打印",delay+1)
    try:
        #wait_for 如果超时，任务会自动取消,wait 超时不会取消
        await asyncio.wait_for(print_timeout,delay)
    except asyncio.TimeoutError:
        print("超时了")


async def main_gather():
    delay = 3
    tasks = [ delay_print(f"等待{i} 秒后打印",i) for i in range(4)]
    fut = asyncio.gather(*tasks)
    print(fut)
    await asyncio.sleep(2)
    try:
        fut.cancel()
        #注意下这里，必须要等待future 结束
        await fut
    except asyncio.CancelledError as e:
        print(fut.done())

        print("未完成任务被取消")


#--------------------------- 取消 -------------------------------
async def cancellable(delay=10):
    loop = asyncio.get_running_loop()
    try:
        now = loop.time()
        print(f"从 {now} 开始休眠，延迟{delay} 秒")
        await asyncio.sleep(delay)
        print(f" 休眠了 {delay} 秒")
    except asyncio.CancelledError:
        print(f"任务在{now} 后 {loop.time()-now} 秒被取消")


async def main_cancel():
    """
    线程不安全的版本
    """
    coro = cancellable()
    task = asyncio.create_task(coro)
    #等待3秒后取消任务
    await asyncio.sleep(3)
    task.cancel()

async def main_cancel_safe():
    """
    线程安全的版本
    """
    coro = cancellable()
    task = asyncio.create_task(coro)
    #等待3秒后取消任务
    await asyncio.sleep(3)

    def canceller(task,fut):
        task.cancel()
        fut.set_result(None)

    loop = asyncio.get_running_loop()
    fut = loop.create_future()
    loop.call_soon_threadsafe(canceller,task,fut)
    await fut


#------------------------------  gather & wait  ------------------------------------------
async def raiser():
    raise Exception("人工抛出异常")


async def main_wait():
    raiser_future = asyncio.ensure_future(raiser())
    say_hello = asyncio.create_task(asyncio.sleep(1,"哈喽,返回了"))
    coros = [raiser_future,say_hello]
    finished,pending = await asyncio.wait(coros,return_when=asyncio.ALL_COMPLETED)
    print(finished)
    print(pending)
    assert raiser_future in finished
    assert raiser_future not in pending
    assert say_hello in finished
    assert say_hello not in pending
    print(raiser_future.exception())
    print(say_hello.result())

# --- Waiting on Multiple Coroutines and Ignoring Exceptions
async def delay_raise(text,delay):
    raise Exception(await asyncio.sleep(delay,result=text))
async def main_exception():
    tasks = [delay_print(f"① 5秒后正常执行",5),
             delay_raise(f"② 5秒后异常发生了",3),
             delay_print(f"③ 5秒后正常执行", 8)
             ]
    res = None
    try:
        # return_exceptions 为 True 时  gather 里的协程执行异常时，会正常返回，而不是抛出异常
        # return_exceptions=False 如果一旦抛出异常 未执行的协程不会被取消，但要注意不要让进程结束
        fut =  asyncio.gather(*tasks,return_exceptions=True)
        #await asyncio.sleep(4)
        #fut.cancel()
        res = await fut
    except asyncio.CancelledError:
        print("任务被取消")
    except Exception as e:
        print("异常捕获",e)
    finally:
        print(res)
    #避免进程结束导致协程任务也结束
    await asyncio.sleep(10)
    print(res)
if __name__ == '__main__':
    asyncio.run(main_exception())